﻿@inherits OwningComponentBase<ICovenantService>

@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Forms
@using Covenant.Core
@using Covenant.Models.Covenant
@using Covenant.Models.Grunts
@using Covenant.Models.Listeners
@inject IJSRuntime IJSRuntime

<EditForm Model="ImplantTemplate" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <div class="form-row">
        <div class="form-group col-md-4">
            <label for="Name">Name</label>
            <input id="Name" name="Name" @bind="ImplantTemplate.Name" class="form-control">
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.Name" /></div>
        </div>
        <div class="form-group col-md-8">
            <label for="Description">Description</label>
            <input id="Description" name="Description" @bind="ImplantTemplate.Description" class="form-control">
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.Description" /></div>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-3">
            <label for="Language">Language</label><br />
            <select id="Language" name="Language" @bind="ImplantTemplate.Language" class="selectpicker show-menu-arrow" data-dropup-auto="false" data-width="auto">
                @foreach (var n in Enum.GetNames(typeof(ImplantLanguage)))
                {
                    <option value="@(((Enum)typeof(ImplantLanguage).GetField(n).GetValue(null)).ToString("d"))">@n</option>
                }
            </select>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.Language" /></div>
        </div>
        <div class="form-group col-md-3">
            <label for="CommType">CommType</label><br />
            <select id="CommType" name="CommType" @bind="ImplantTemplate.CommType" class="selectpicker show-menu-arrow" data-dropup-auto="false" data-width="auto">
                @foreach (var n in Enum.GetNames(typeof(CommunicationType)))
                {
                    <option value="@(((Enum)typeof(CommunicationType).GetField(n).GetValue(null)).ToString("d"))">@n</option>
                }
            </select>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.CommType" /></div>
        </div>
        <div class="form-group col-md-3">
            <label for="ImplantDirection">ImplantDirection</label><br />
            <select id="ImplantDirection" name="ImplantDirection" @bind="ImplantTemplate.ImplantDirection" class="selectpicker show-menu-arrow" data-dropup-auto="false" data-width="auto">
                @foreach (var n in Enum.GetNames(typeof(ImplantDirection)))
                {
                    <option value="@(((Enum)typeof(ImplantDirection).GetField(n).GetValue(null)).ToString("d"))">@n</option>
                }
            </select>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.ImplantDirection" /></div>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-3">
            <label for="CompatibleListenerTypes">CompatibleListenerTypes</label><br />
            <select id="CompatibleListenerTypes" name="CompatibleListenerTypes" class="selectpicker show-menu-arrow" multiple data-dropup-auto="false" data-width="auto" data-live-search="true" data-selected-text-format="count > 2">
                @foreach (ListenerType lt in GetListenerTypes())
                {
                    <option value="@lt.Id">@lt.Name</option>
                }
            </select>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.CompatibleListenerTypes" /></div>
        </div>
        @if (ImplantTemplate.Language == ImplantLanguage.CSharp)
        {
            <div class="form-group col-md-3">
                <label for="CompatibleDotNetVersions">CompatibleDotNetVersions</label><br />
                <select id="CompatibleDotNetVersions" name="CompatibleDotNetVersions" class="selectpicker show-menu-arrow" multiple data-dropup-auto="false" data-width="auto" data-live-search="true" data-selected-text-format="count > 2">
                    @foreach (var n in Enum.GetNames(typeof(Common.DotNetVersion)))
                    {
                        if (Enum.TryParse<Common.DotNetVersion>(n, out Common.DotNetVersion version) && this.ImplantTemplate.CompatibleDotNetVersions.Contains(version))
                        {
                            <option selected value="@(((Enum)typeof(Common.DotNetVersion).GetField(n).GetValue(null)).ToString("d"))">@n</option>
                        }
                        else
                        {
                            <option value="@(((Enum)typeof(Common.DotNetVersion).GetField(n).GetValue(null)).ToString("d"))">@n</option>
                        }
                    }
                </select>
                <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.CompatibleDotNetVersions" /></div>
            </div>
        }
    </div>
    <div class="form-row">
        <div class="form-group col-md-12">
            <label for="StagerCode">StagerCode</label>
            <textarea @ref="CodeMirrorElements[0]" id="StagerCode" name="StagerCode" value="@ImplantTemplate.StagerCode" @onchange="e => OnSetStagerCode(e)" rows="5" class="form-control code-mirror-csharp"></textarea>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.StagerCode" /></div>
        </div>
    </div>
    <div class="form-row">
        <div class="form-group col-md-12">
            <label for="ExecutorCode">ExecutorCode</label>
            <textarea @ref="CodeMirrorElements[1]" id="ExecutorCode" name="ExecutorCode" value="@ImplantTemplate.ExecutorCode" @onchange="e => OnSetExecutorCode(e)" rows="5" class="form-control code-mirror-csharp"></textarea>
            <div class="text-danger"><ValidationMessage For="() => ImplantTemplate.ExecutorCode" /></div>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">
        <span class="fe fe-@SubmitIcon"></span>@SubmitLabel
    </button>
</EditForm>

@code {
    private ImplantTemplate _ImplantTemplate;
    [Parameter]
    public ImplantTemplate ImplantTemplate
    {
        get
        {
            return _ImplantTemplate;
        }
        set
        {
            if (value.Id > 0)
            {
                _ImplantTemplate = Service.GetImplantTemplate(value.Id).WaitResult();
            }
            else
            {
                _ImplantTemplate = value;
            }
        }
    }

    [Parameter]
    public string SubmitIcon { get; set; } = "edit";

    [Parameter]
    public string SubmitLabel { get; set; } = "Edit";

    [Parameter]
    public EventCallback<ImplantTemplate> OnSubmit { get; set; }

    [CascadingParameter]
    public Theme Theme { get; set; }

    private IList<ElementReference> CodeMirrorElements { get; set; } = GetElementReferenceList(2);

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            foreach (ElementReference CodeMirrorElement in CodeMirrorElements)
            {
                await IJSRuntime.InvokeAsync<string>("InitializeCodeMirror", CodeMirrorElement, Theme.CodeMirrorTheme.ToString());
            }
        }
        await IJSRuntime.InvokeAsync<string>("InitializeSelectPicker", new object[] { "#Language.selectpicker", ((int)Enum.Parse(typeof(ImplantLanguage), ImplantTemplate.Language.ToString())).ToString() });
        await IJSRuntime.InvokeAsync<string>("InitializeSelectPicker", new object[] { "#CommType.selectpicker", ((int)Enum.Parse(typeof(CommunicationType), ImplantTemplate.CommType.ToString())).ToString() });
        await IJSRuntime.InvokeAsync<string>("InitializeSelectPicker", new object[] { "#ImplantDirection.selectpicker", ((int)Enum.Parse(typeof(ImplantDirection), ImplantTemplate.ImplantDirection.ToString())).ToString() });
        await IJSRuntime.InvokeAsync<string>("InitializeSelectPicker", new object[] { "#CompatibleListenerTypes.selectpicker", ImplantTemplate.CompatibleListenerTypes.Select(CLT => CLT.Id.ToString()).ToArray() });
        if (ImplantTemplate.Language == ImplantLanguage.CSharp)
        {
            await IJSRuntime.InvokeAsync<string>("InitializeSelectPicker", new object[] { "#CompatibleDotNetVersions.selectpicker", ImplantTemplate.CompatibleDotNetVersions.Select(CDNV => ((int)Enum.Parse(typeof(Common.DotNetVersion), CDNV.ToString())).ToString()).ToArray() });
        }
    }

    private static IList<ElementReference> GetElementReferenceList(int size)
    {
        IList<ElementReference> references = new List<ElementReference>();
        for (int i = 0; i < size; i++)
        {
            references.Add(new ElementReference());
        }
        return references;
    }

    private IEnumerable<ListenerType> GetListenerTypes()
    {
        return Service.GetListenerTypes().WaitResult();
    }

    public async Task<List<ListenerTypeImplantTemplate>> GetCompatibleListenerTypeImplantTemplates()
    {
        string[] clts = await IJSRuntime.InvokeAsync<string[]>("GetValue", new object[] { "#CompatibleListenerTypes" });
        IEnumerable<int> ids = clts.Where(id => int.TryParse(id, out _)).Select(sid => int.Parse(sid));
        List<ListenerTypeImplantTemplate> types = new List<ListenerTypeImplantTemplate>();
        foreach (int id in ids)
        {
            types.Add(new ListenerTypeImplantTemplate
            {
                ListenerTypeId = id,
                ListenerType = await Service.GetListenerType(id),
                ImplantTemplateId = this.ImplantTemplate.Id,
                ImplantTemplate = this.ImplantTemplate
            });
        }
        return types;
    }

    private async Task<List<Common.DotNetVersion>> GetCompatibleDotNetVersions()
    {
        string[] ids = await IJSRuntime.InvokeAsync<string[]>("GetValue", new object[] { "#CompatibleDotNetVersions" });
        return ids.Where(id => Enum.TryParse<Common.DotNetVersion>(id, out _)).Select(id => Enum.Parse<Common.DotNetVersion>(id)).ToList();
    }

    private async Task OnSetStagerCode(ChangeEventArgs e)
    {
        this.ImplantTemplate.CompatibleDotNetVersions = await this.GetCompatibleDotNetVersions();
        this.ImplantTemplate.SetListenerTypeImplantTemplates(await this.GetCompatibleListenerTypeImplantTemplates());
        this.ImplantTemplate.StagerCode = e.Value.ToString();
    }

    private async Task OnSetExecutorCode(ChangeEventArgs e)
    {
        this.ImplantTemplate.CompatibleDotNetVersions = await this.GetCompatibleDotNetVersions();
        this.ImplantTemplate.SetListenerTypeImplantTemplates(await this.GetCompatibleListenerTypeImplantTemplates());
        this.ImplantTemplate.ExecutorCode = e.Value.ToString();
    }

    private async Task Submit()
    {
        this.ImplantTemplate.CompatibleDotNetVersions = await GetCompatibleDotNetVersions();
        this.ImplantTemplate.SetListenerTypeImplantTemplates(await GetCompatibleListenerTypeImplantTemplates());
        await this.OnSubmit.InvokeAsync(this.ImplantTemplate);
    }
}